﻿using System.Security.Cryptography;

namespace Basic.Base.Encryption
{
    public class AESHelper
    {
        /// <summary>
        /// 初始化秘钥
        /// </summary>
        public byte[] AesKey { get; set; } = Encoding.ASCII.GetBytes("XXXXXXWATERGROUP");

        /// <summary>
        /// 初始化向量
        /// </summary>
        public byte[] AesIV { get; set; } = Encoding.ASCII.GetBytes("XXXXXXWATERGROUP");

        public CipherMode AesCipherMode { get; set; } = CipherMode.ECB;

        public PaddingMode AesPaddingMode { get; set; } = PaddingMode.PKCS7;

        public AESHelper() { }

        public AESHelper(byte[] key, byte[] iv, CipherMode cipher = CipherMode.ECB, PaddingMode padding = PaddingMode.PKCS7)
        {
            AesKey = key;
            AesIV = iv;
            AesCipherMode = cipher;
            AesPaddingMode = padding;

            SetByteArray(AesIV, 16);
        }

        /// <summary>
        /// AES-128-ECB 加密，加密数据的分组长度为 16 字节，如需对数据进行填充补齐，采用 PKCS7Padding 填充方式
        /// 加密字段：数据包，不包含响应码
        /// </summary>
        /// <returns></returns>
        public byte[]? AESEncode(byte[] value)
        {
            using Aes aes = InitializeAES(value);
            using var cryptoTransform = aes.CreateEncryptor();
            var resArray = cryptoTransform.TransformFinalBlock(value, 0, value.Length);
            return resArray;
        }

        /// <summary>
        /// AES-128-ECB 解密
        /// </summary>
        /// <param name="value"></param>
        /// <param name="key"></param>
        /// <param name="isBaseKey"></param>
        /// <returns></returns>
        public Span<byte> AESDecode(Span<byte> value)
        {
            using Aes aes = InitializeAES(value);
            using var cryptoTransform = aes.CreateDecryptor();
            return cryptoTransform.TransformFinalBlock(value.ToArray(), 0, value.Length);
        }

        /// <summary>
        /// 初始化AES算法参数
        /// </summary>
        /// <param name="value">数据</param>
        /// <param name="key">秘钥</param>
        /// <param name="isBaseKey">是否使用初始秘钥</param>
        /// <returns>Aes</returns>
        /// <exception cref="ArgumentNullException"></exception>
        private Aes InitializeAES(Span<byte> value)
        {
            if (value.IsEmpty)
                throw new ArgumentNullException("数据包为空");

            Aes aes = Aes.Create();
            aes.Mode = AesCipherMode;
            aes.Padding = AesPaddingMode;
            aes.IV = SetByteArray(AesIV, 16);
            aes.Key = AesKey;

            return aes;
        }

        private byte[] SetByteArray(byte[] raw, int length)
        {
            if (raw.Length > 16)
                return raw.Sub(0, 16);
            else if (raw.Length == 16)
                return raw;

            byte[] bytes = new byte[16];
            Array.Copy(raw, 0, bytes, 0, raw.Length);
            return bytes;
        }

    }
}
